package org.dromara.web.service

import cn.dev33.satoken.secure.BCrypt
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
import org.dromara.common.core.constant.Constants
import org.dromara.common.core.constant.GlobalConstants
import org.dromara.common.core.domain.model.RegisterBody
import org.dromara.common.core.enums.UserType
import org.dromara.common.core.exception.user.CaptchaException
import org.dromara.common.core.exception.user.CaptchaExpireException
import org.dromara.common.core.exception.user.UserException
import org.dromara.common.core.utils.MessageUtils
import org.dromara.common.core.utils.ServletUtils
import org.dromara.common.core.utils.SpringUtils
import org.dromara.common.core.utils.StringUtils
import org.dromara.common.log.event.LogininforEvent
import org.dromara.common.redis.utils.RedisUtils
import org.dromara.common.tenant.helper.TenantHelper
import org.dromara.common.web.config.properties.CaptchaProperties
import org.dromara.system.domain.SysUser
import org.dromara.system.domain.bo.SysUserBo
import org.dromara.system.mapper.SysUserMapper
import org.dromara.system.service.ISysUserService
import org.springframework.stereotype.Service

/**
 * 注册校验方法
 *
 *@author LikeYouDo
 *@date 2025/1/5 22:30
 */
@Service
class SysRegisterService(
    private val userService: ISysUserService,
    private val userMapper: SysUserMapper,
    private val captchaProperties: CaptchaProperties,
) {
    /**
     * 注册
     */
    fun register(registerBody: RegisterBody) {
        val tenantId = registerBody.tenantId
        val username = registerBody.username
        val password = registerBody.password
        // 校验用户类型是否存在
        val userType = UserType.getUserType(registerBody.userType).userType

        val captchaEnabled = captchaProperties.enable
        // 验证码开关
        if (captchaEnabled) {
            validateCaptcha(tenantId, username, registerBody.code, registerBody.uuid)
        }
        val sysUser = SysUserBo().apply {
            userName = username
            nickName = username
            this.password = BCrypt.hashpw(password)
            this.userType = userType
        }

        val exist = TenantHelper.dynamic<Boolean>(tenantId) {
            userMapper.exists(
                LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getUserName, sysUser.userName)
            )
        }
        if (exist) {
            throw UserException("user.register.save.error", username)
        }
        val regFlag = userService.registerUser(sysUser, tenantId)
        if (!regFlag) {
            throw UserException("user.register.error")
        }
        recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"))
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     */
    fun validateCaptcha(tenantId: String?, username: String, code: String?, uuid: String?) {
        val verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "")
        val captcha = RedisUtils.getCacheObject<String?>(verifyKey)
        RedisUtils.deleteObject(verifyKey)
        if (captcha == null) {
            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))
            throw CaptchaExpireException()
        }
        if (!StringUtils.equalsIgnoreCase(code, captcha)) {
            recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))
            throw CaptchaException()
        }
    }

    /**
     * 记录登录信息
     *
     * @param tenantId 租户ID
     * @param username 用户名
     * @param status   状态
     * @param message  消息内容
     * @return
     */
    private fun recordLogininfor(tenantId: String?, username: String, status: String, message: String) =
        SpringUtils.context().publishEvent(LogininforEvent().apply {
            this.tenantId = tenantId
            this.username = username
            this.status = status
            this.message = message
            request = ServletUtils.getRequest()
        })

}
